/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FLASH_DRV_H
#define FLASH_DRV_H

/*!
 * @file flash_drv.h
 * @brief This file declares flash driver interfaces
 */

/*!
 * @addtogroup flash_drv
 * @{
 */

/*******Includes***************************************************************/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "errcodes.h"
#include "device_registers.h"

/*******Definitions************************************************************/
/*!
 * @brief Flash types of flash area
 */
typedef enum {
    FLASH_AREA_PFLASH = 0U,       /*!< Pflash area */
    FLASH_AREA_DFLASH = 1U,       /*!< Dflash area */
    FLASH_AREA_OPTION_BYTE = 2U   /*!< Option Byte area */
} flash_area_type_t;

/*!
 * @brief Flash types of chip uuid
 */
typedef struct {
    uint32_t lowUid;             /*!< bit:0~31 of UUID */
    uint32_t midLowUid;          /*!< bit:32~63 of UUID */
    uint32_t midHighUid;         /*!< bit:64~95 of UUID */
    uint32_t highUid;            /*!< bit:96~127 of UUID */
} flash_chip_uuid_type_t;

/*!
 * @brief Flash types of block
 */
typedef enum {
    PFLASH_BLOCK0 = 0U,
#if (CONFIG_PFLASH_NUMBER_OF_BLOCK == 2U)
    PFLASH_BLOCK1 = 1U,
#endif
    DFLASH_BLOCK0 = 2U
} flash_block_type_t;

#if (CONFIG_FLASH_DEBUG_PROTECT_FEATURE == 1U)
/*!
 * @brief Flash types of debug key
 */
typedef struct {
    uint32_t key0;               /*!< bit:0~31 of debug key */
    uint32_t key1;               /*!< bit:32~63 of debug key */
    uint32_t key2;               /*!< bit:64~95 of debug key */
    uint32_t key3;               /*!< bit:96~127 of debug key */
    uint32_t key4;               /*!< bit:128~159 of debug key */
    uint32_t key5;               /*!< bit:160~191 of debug key */
    uint32_t key6;               /*!< bit:192~223 of debug key */
    uint32_t key7;               /*!< bit:224~255 of debug key */
} flash_debug_auth_key_t;
#endif

#if (CONFIG_FLASH_AB_SWAP_FEATURE == 1U)
/*!
 * @brief Flash types swapping
 */
typedef enum {
    PFLASH_BLOCK_NO_SWAPPING = 0U,
    PFLASH_BLOCK_SWAPPING = 1U
} flash_block_swap_t;
#endif

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Set flash frequency
 *
 * @param[in] freq: The frequency to be set in mHz
 * @return None
 */
void FLASH_SetFlashClock(uint16_t freq);

/*!
 * @brief Unlock the flash Program Erase Controller
 *
 * @param[in] area: Area in flash(PFlash/DFlash/Option Byte)
 * @return void
 */
void FLASH_Unlock(flash_area_type_t area);

/*!
 * @brief Lock the flash Program Erase Controller
 *
 * @param[in] area: Area in flash(PFlash/DFlash/Option Byte)
 * @return None
 */
void FLASH_Lock(flash_area_type_t area);

/*!
 * @brief Read word from the flash specified address
 *
 * @param[in] address: Specified address
 * @return Data in the specified address
 */
uint32_t FLASH_ReadWord(uint32_t address);

/*!
 * @brief Read data from the flash specified address
 *
 * @param[in] startAddress: Start address
 * @param[out] dataBuffer: Point to the data stored
 * @param[in] size: Size
 * @return None
 */
void FLASH_Read(uint32_t startAddress, uint8_t* dataBuffer, uint32_t size);

/*!
 * @brief Programs a phrase(8 byte) at a specified address
 *
 * @param[in] address: Specifies the address to be programmed
 * @param[in] dataLow: low word data of a phrase
 * @param[in] dataHigh: high word data of a phrase
 * @return Error or success status
 */
errcode_t FLASH_Program(uint32_t address, uint32_t dataLow, uint32_t dataHigh);

/*!
 * @brief Programs page at a specified address
 *
 * @param[in] address: Specifies the address to be programmed
 * @param[in] buffer: Pointer to the data to be programmed
 * @param[in] length: Number of bytes to be programmed
 * @return Error or success status
 */
errcode_t FLASH_ProgramSection(uint32_t startAddress, uint8_t* buffer, uint16_t length);

/*!
 * @brief Programs option byte
 *
 * @param[in] address: Specifies the option byte address to be programmed
 * @param[in] buffer: Pointer to the data to be programmed
 * @param[in] length: Number of bytes to be programmed
 * @return Error or success status
 */
errcode_t FLASH_ProgramOptionByte(uint32_t address, uint8_t* buffer, uint16_t length);

/*!
 * @brief Erases a specified flash page
 *
 * @param[in] pageAddress: The page address to be erased
 * @return Error or success status
 */
errcode_t FLASH_ErasePage(uint32_t pageAddress);

/*!
 * @brief Erases option byte
 *
 * @param[in] address: option byte address
 * @return Error or success status
 */
errcode_t FLASH_EraseOptionByte(uint32_t address);

/*!
 * @brief Erases block
 *
 * @param[in] block: The block that needs to be erased
 * @return Error or success status
 */
errcode_t FLASH_EraseBlock(flash_block_type_t block);

/*!
 * @brief Verify a specified flash page if is erased successfully
 *
 * @param[in] pageAddress: The page address to be verified.
 * @return Error or success status
 */
errcode_t FLASH_VerifyPage(uint32_t pageAddress);

/*!
 * @brief Verify block
 *
 * @param[in] block: The block that needs to be verified
 * @return Error or success status
 */
errcode_t FLASH_VerifyBlock(flash_block_type_t block);

/*!
 * @brief Enable/Disable write protection specified pages
 * @param[in] area:The area to be protected
 * @param[in] startPageNumber: Start page
 * @param[in] pageLength: Length of pages
 * @param[in] enable: Enable or disable write protection
 * @return Error or success status
 */
errcode_t FLASH_SetWriteProtect(flash_block_type_t area, uint32_t startPageNumber, uint32_t pageLength, bool enable);

/*!
 * @brief Enable write protection specified pages by register
 *
 * @param[in] startPageNumber: Start page
 * @param[in] pageLength: Length of pages
 * @return Error or success status
 */
errcode_t FLASH_EnableWriteProtectRegister(flash_block_type_t area, uint32_t startPageNumber, uint32_t pageLength);

#if (CONFIG_FLASH_READ_PROTECT_FEATURE == 1U)
/*!
 * @brief Enable/Disable read protection
 *
 * @param[in] enable: Enable disable write protection
 * @return Error or success status
 */
errcode_t FLASH_SetReadProtect(bool enable);

/*!
 * @brief Get current read protection status
 *
 * @param[in] None
 * @return -true: Read protection is enable
 *         -false: Read protection is disable
 */
bool FLASH_GetReadProtectStatus(void);

#elif (CONFIG_FLASH_DEBUG_PROTECT_FEATURE == 1U)
/*!
 * @brief Enable/Disable debug protection
 *
 * @param[in] enable: Enable disable write protection
 * @param[in] key: Authorization key
 * @return Error or success status
 */
errcode_t FLASH_SetDebugProtect(bool enable, flash_debug_auth_key_t key);

/*!
 * @brief Get debug status
 *
 * @param[in] None
 * @return enable(true) or disable(false)
 */
bool FLASH_GetDebugStatus(void);

/*!
 * @brief Authenticate debug
 *
 * @param[in] debugkey:key
 * @return Protection(true) or non-protection(false)
 */
errcode_t FLASH_AuthenticateDebugKey(flash_debug_auth_key_t debugKey);
#endif

#if (CONFIG_FLASH_AB_SWAP_FEATURE == 1U)
/*!
 * @brief Authenticate debug
 *
 * @param[in] enable:Enable or disable A/B Swap function
 * @return Error or success status
 */
errcode_t FLASH_SetAbSwap(bool enable);

/*!
 * @brief Get A/B swap enable status
 *
 * @param[in] None
 * @return enable or disable
 */
bool FLASH_GetAbSwapEnableStatus(void);

/*!
 * @brief Swap pflash
 *
 * @param[in] None
 * @return Error or success status
 */
errcode_t FLASH_SwapPflash(void);

/*!
 * @brief Get Pflash swapping mode
 *
 * @param[in] None
 * @return PFLASH_BLOCK_NO_SWAPPING or PFLASH_BLOCK_SWAPPING
 */
flash_block_swap_t FLASH_GetPflashSwapStatus(void);

#endif
/*!
 * @brief Get chip universally unique identifier
 *
 * @param[out] Pointer to uuid structure
 * @return None
 */
void FLASH_GetChipUniqueIdentifier(flash_chip_uuid_type_t* uuid);

/*!
 * @brief Get chip memory(pflash & sram) size information
 *
 * @param[out] Pointer to program flash size information
 * @param[out] Pointer to sram size information
 * @return None
 */
void FLASH_GetChipMemorySizeInfo(uint16_t* pflashSizeInfo, uint16_t* sramSizeInfo);

/*!
 * @brief Get chip pins information
 *
 * @param[in] Pointer to pins information
 * @return void
 */
void FLASH_GetChipPinInfo(uint16_t* pinInfo);

/*!
 * @brief Get chip Bandgap offset
 *
 * @param[in] None
 * @return Bandgap offset
 */
int16_t FLASH_GetBandgapOffset(void);

/*!
 * @brief Program setction asynchronously
 *
 * @param[in] address: Specifies the address to be programmed
 * @param[in] buffer: Pointer to the data to be programmed
 * @param[in] length: Number of bytes to be programmed
 * @return Busy or success
 */
errcode_t FLASH_AsyncProgramSection(uint32_t startAddress, uint8_t* buffer, uint16_t length);

/*!
 * @brief Erase the page asynchronously
 *
 * @param[in] pageAddress: The page address to be erased
 * @return Busy or success
 */
errcode_t FLASH_AsyncErasePage(uint32_t pageAddress);

/*!
 * @brief Erase the block asynchronously
 *
 * @param[in] block: The block that needs to be erased
 * @return Busy or success
 */
errcode_t FLASH_AsyncEraseBlock(flash_block_type_t block);

/*!
 * @brief Gets the status of the asynchronous operation
 *
 * @param[in] void
 * @return ERR_BUSY ERR_SUCCESS ERR_ERROR
 */
errcode_t FLASH_GetAsyncOperateStatus(void);

#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* FLASH_DRV_H */

/*******EOF********************************************************************/
